package org.epidroid.epidroid.androsoul.engine.service;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.epidroid.epidroid.R;
import org.epidroid.epidroid.androsoul.engine.AndroSoul;
import org.epidroid.epidroid.androsoul.engine.communication.Connection;
import org.epidroid.epidroid.androsoul.engine.communication.Connection.State;
import org.epidroid.epidroid.androsoul.engine.contacts.ContactGroup;
import org.epidroid.epidroid.androsoul.engine.contacts.NetsoulContact;
import org.epidroid.epidroid.androsoul.engine.conversation.OpenedConversations;
import org.epidroid.epidroid.androsoul.engine.utils.AndroSoulNotificationsListener;
import org.epidroid.epidroid.androsoul.engine.utils.NetworkConnectivityListener;
import org.epidroid.epidroid.androsoul.ui.AndroSoulActivity;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;

public class AndroSoulService extends Service implements IAndroSoulService {

	AndroSoul _androSoul = null;
	Handler _handler = null;

	private AndroSoulServiceBinder _binder;
	private List<IAndroSoulServiceListener> _listeners = null;
	private NotificationManager _mNM;

	AndroSoulNotificationsListener _notifListener = null;
	private NetworkConnectivityListener _connectivityListener = null;

	public static final int NOTIFICATION = 0;
	public static final int NOTIFICATION_MSG = 0;

	private String _login = null;
	private String _pass = null;

	@Override
	public void onCreate() {
		_mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		_binder = new AndroSoulServiceBinder(this);
		showServiceRunningNotification(false);
		_onStart();

		_notifListener = new AndroSoulNotificationsListener(_mNM, this);
		addListener(_notifListener);

		createConnectivityListener();
	}

	private void createConnectivityListener() {
		_connectivityListener = new NetworkConnectivityListener();
		_connectivityListener.registerHandler(new Handler() {
			@Override
			public void handleMessage(Message msg) {
				Log.v(AndroSoul.LOGCAT, "Received message: " + msg.what);
				switch (_connectivityListener.getState()) {
				case CONNECTED:
					Log.v(AndroSoul.LOGCAT, "We are now connected");
					if ((null != _login) && (null != _pass)
							&& (getConnectionState() == Connection.State.OFF)) {
						Log.v(AndroSoul.LOGCAT, "connecting!");
						connect(_login, _pass);
					}
					break;
				case NOT_CONNECTED:
					Log.v(AndroSoul.LOGCAT, "We are now disconnected");
					logout();
					break;
				}
			}
		}, 1);
		_connectivityListener.startListening(this);
	}

	@Override
	public IBinder onBind(Intent intent) {
		return _binder;
	}

	public void _onStart() {
		_handler = new Handler() {
			@Override
			public void handleMessage(final Message msg) {
				notifyListeners(msg);
			}
		};

		// if the androsoul instance is not created yet, create it
		if (_androSoul == null)
			_androSoul = new AndroSoul(_handler);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		_onStart();
		return START_STICKY;
	}

	@Override
	public void onDestroy() {
		Log.v(AndroSoul.LOGCAT, "service destroy");
		_mNM.cancel(NOTIFICATION);
		_connectivityListener.stopListening();

		super.onDestroy();
	}

	/*
	 * (non-Javadoc) Add a listener
	 * 
	 * @see org.epidroid.epidroid.androsoul.androsoulservice.IAndroSoulService#
	 * addListener
	 * (org.epidroid.epidroid.androsoul.androsoulservice.IAndroSoulServiceListener
	 * )
	 */
	public void addListener(IAndroSoulServiceListener listener) {
		if (_listeners == null) {
			_listeners = new ArrayList<IAndroSoulServiceListener>();
		}
		_listeners.add(listener);
	}

	/*
	 * Delete a listener (non-Javadoc)
	 * 
	 * @see org.epidroid.epidroid.androsoul.androsoulservice.IAndroSoulService#
	 * removeListener
	 * (org.epidroid.epidroid.androsoul.androsoulservice.IAndroSoulServiceListener
	 * )
	 */
	public void removeListener(IAndroSoulServiceListener listener) {
		if (_listeners != null) {
			_listeners.remove(listener);
		}
	}

	/**
	 * Notify all listeners of an action
	 * 
	 * @param data
	 *            data to be notified
	 */
	private void notifyListeners(Message data) {
		if (_listeners != null) {
			for (IAndroSoulServiceListener listener : _listeners) {
				listener.dataChanged(data);
			}
		}
	}

	/**
	 * Show a notification while this service is running.
	 */
	public void showServiceRunningNotification(boolean connected) {

		String text = connected ? getString(R.string.online) : getString(R.string.offline);

		// Set the icon, scrolling text and timestamp
		Notification notification = new Notification(R.drawable.androsoul,
				text, System.currentTimeMillis());

		notification.flags |= (Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR);

		// The PendingIntent to launch our activity if the user selects this
		// notification
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
				new Intent(this, AndroSoulActivity.class), 0);

		// Set the info for the views that show in the notification panel.
		notification.setLatestEventInfo(this, "AndroSoul", text, contentIntent);

		// Send the notification.
		// TODO: there are several notifications shown.
		setForeground(true);
		_mNM.notify(NOTIFICATION, notification);
		startForeground(NOTIFICATION, notification);
	}

	@Override
	public State getConnectionState() {
		return _androSoul.getState();
	}

	@Override
	public Boolean connect(String login, String pass) {
		this._login = login;
		this._pass = pass;
		return _androSoul.connect(login, pass);
	}

	@Override
	public void logout() {
		_androSoul.UserLogout();
		showServiceRunningNotification(false);
		this.stopSelf();
	}

	@Override
	public void setMyState(String state) {
		_androSoul.changeUserState(state);
	}

	@Override
	public NetsoulContact getMySelf() {
		return _androSoul._myself;
	}

	@Override
	public void setMyComment(String comment) {
		_androSoul.set_comment(comment);
	}

	@Override
	public void setMyLocation(String location) {
		_androSoul.set_location(location);
	}

	@Override
	public String getMyLocation() {
		return _androSoul.get_location();
	}

	@Override
	public NetsoulContact getContactFromName(String name) {
		return _androSoul.getDictionary().get(name);
	}

	@Override
	public void contactsLoad(FileInputStream fis) {
		_androSoul.contactsLoad(fis);
	}

	@Override
	public void contactsSave(FileOutputStream fos) {
		_androSoul.contactsSave(fos);
	}

	@Override
	public List<ContactGroup> getGroupsList() {
		return _androSoul.getContacts().getGroups();
	}

	@Override
	public NetsoulContact addContact(String name, ContactGroup group) {
		return _androSoul.addContact(name, group);
	}

	@Override
	public void addContacts(List<String> contacts, ContactGroup group) {
		_androSoul.addContacts(contacts, group);
	}

	@Override
	public NetsoulContact addContact(String name) {
		return _androSoul.getDictionary().createContact(name);
	}

	@Override
	public void deleteContact(NetsoulContact contact, ContactGroup group) {
		_androSoul.deleteContact(contact, group);
	}

	@Override
	public void deleteGroup(ContactGroup group) {
		_androSoul.deleteGroup(group);
	}

	@Override
	public void clearContacts() {
		_androSoul.getContacts().clear();
	}

	@Override
	public ContactGroup addGroup(String name) {
		return _androSoul.addGroup(name);
	}

	@Override
	public ContactGroup getGroupFromName(String name) {
		return _androSoul.findGroup(name);
	}

	@Override
	public ArrayList<ContactGroup> getContactGroups(NetsoulContact contact) {
		return _androSoul.getContactGroups(contact);
	}

	@Override
	public Boolean renameGroup(ContactGroup group, String name) {
		return _androSoul.renameGroup(group, name);
	}

	@Override
	public void sendListUser(String name) {
		_androSoul.sendListUsers(name);
	}

	@Override
	public void openConversation(NetsoulContact contact) {
		_androSoul.getOpenedConversations().openConversation(contact);
	}

	@Override
	public void closeConversation(NetsoulContact contact) {
		_androSoul.getOpenedConversations().closeConversation(contact);
	}

	@Override
	public OpenedConversations getOpenedConversations() {
		return _androSoul.getOpenedConversations();
	}

	@Override
	public void sendContactWizz(NetsoulContact contact) {
		_androSoul.sendContactWizz(contact);
	}

	@Override
	public void sendContactMessage(NetsoulContact contact, String content) {
		_androSoul.sendContactMsg(contact, content);

	}

	@Override
	public void sendContactIsTyping(NetsoulContact contact) {
		_androSoul.sendContactIsTyping(contact);
	}

	@Override
	public void sendContactStopTyping(NetsoulContact contact) {
		_androSoul.sendContactStopTyping(contact);
	}

	@Override
	public void enableWizz(boolean value) {
		_androSoul.enableWizz(value);
	}

	@Override
	public void enableNotifContactLogin(boolean value) {
		_notifListener.enableNotifContactLogin(value);
	}

	@Override
	public void enableNotifContactLogoff(boolean value) {
		_notifListener.enableNotifContactLogoff(value);
	}

	@Override
	public void enableNotifMessageReceived(boolean value) {
		_notifListener.enableNotifMessageReceived(value);
	}

	@Override
	public void enableNotifs(boolean enable) {
		_notifListener.enableNotifs(enable);
	}

	@Override
	public void ping() {
		_androSoul.ping();
	}
}
